#ifndef MEMMAP_H
#define MEMMAP_H

#include <string.h>

#include "types.h"

#define BITREV_32(x) ((((x) & 0xff000000) >> 24) \
                    | (((x) & 0x00ff0000) >>  8) \
                    | (((x) & 0x0000ff00) <<  8) \
                    | (((x) & 0x000000ff) << 24))

#define BITREV_16(x) ((((x) & 0xff00) >> 8) \
                    | (((x) & 0x00ff) << 8))

typedef enum
{
    MEMSTATE_INVALID,
    MEMSTATE_READY,
    MEMSTATE_FUNC,
    MEMSTATE_TRACE
} MemState;

typedef struct
{
    char *ptr;
    s32 vaddr;
    MemState state;
    s32 (*func_read)(u32 addr);
    void (*func_write)(u32 addr, u32 value);
} MemRegion;

typedef enum
{
    MRTYPE_INVALID,
    MRTYPE_MEMORY,
    MRTYPE_FUNC
} MemRegionType;

typedef struct
{
    const char *name; 
    MemRegionType type;
    u32 start, end;
    char *memPointer;
    s32 (*func_read)(u32 addr);
    void (*func_write)(u32 addr, u32 value);
} MemRegionInfo;

#define MEMTABLE_BITS  17
#define MEMTABLE_SHIFT (32 - MEMTABLE_BITS) /* 15 */
#define MEMTABLE_SIZE  (1 << MEMTABLE_BITS)
#define MEMTABLE_MASK  ~((1 << MEMTABLE_SHIFT) - 1)

typedef enum
{
    MEMERR_NONE,
    MEMERR_NOTHINGMAPPED
} MemoryError;

typedef struct
{
    MemRegion memTable[MEMTABLE_SIZE];
    u32 numRegions;
} MemMap;

void memMap_addRegion(MemRegionInfo region);
void memMap_delRegion(u32 start);
void memMap_init();
void memMap_free();

s8    mem_read8       (u32 address);
s16   mem_read16      (u32 address);
s32   mem_read32      (u32 address);
s32   mem_read32_noerr(u32 address);
float mem_readFloat   (u32 address);
char *mem_readStr     (u32 address);
void  mem_write8      (u32 address, u8    value);
void  mem_write16     (u32 address, s16   value);
void  mem_write32     (u32 address, s32   value);
void  mem_write64     (u32 address, u64   value);
void  mem_writeFloat  (u32 address, float value);

void  mem_readStruct  (u32 address, void *ptr, u32 size);
void  mem_writeStruct (u32 address, void *ptr, u32 size);

void mem_freeStr(char *str);

u8 mem_isOk(u32 address);

#endif

